﻿#include "FITKCCXAdaptorSurface.h"
#include "FITKCalculixINPWriter.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurface.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurfaceNode.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurfaceElement.h"
#include "FITK_Interface/FITKInterfaceModel/FITKComponentManager.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAssembly.h"
#include "FITK_Kernel/FITKCore/FITKEnumTransformer.hpp"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaSurfaceLabel.h"

namespace IO
{

    QString FITKCCXAdaptorSurface::getAdaptorClass()
    {
        return "IO::FITKCCXAdaptorSurface";
    }

    void FITKCCXAdaptorSurface::setSetSurfManaget(Interface::FITKComponentManager* manager)
    {
        _setSurfManager = manager;
    }

    void FITKCCXAdaptorSurface::setAssemblyPartManager(Interface::FITKAbaAssembly* ass, AbaqusData::FITKAbaqusPartManager* part)
    {
        _assemblyManager = ass;
        _partManager = part;
        //设置set管理器
        if (_assemblyManager)
            _setSurfManager = _assemblyManager->getComponentManager();
    }

    void FITKCCXAdaptorSurface::setSurfaceNumber(const int &surfaceNumber)
    {
        _surfaceNumber = surfaceNumber;
    }

    int FITKCCXAdaptorSurface::getSurfaceNumber()
    {
        return _surfaceNumber;
    }

    void FITKCCXAdaptorSurface::setModelInfoManager(FITKCCXModelInforManager* modelInfoManager)
    {
        _modelInfoManager = modelInfoManager;
    }

    void FITKCCXAdaptorSurface::setMappingKeyDataObjectID(const int& mappingDataObectID)
    {
        _mappingKeyDataObjectID = mappingDataObectID;
    }

    bool FITKCCXAdaptorSurface::adaptR()
    {
        return false;
    }

    bool FITKCCXAdaptorSurface::adaptW()
    {
        // 获取数据
        Interface::FITKMeshSurface* surfaceData = dynamic_cast<Interface::FITKMeshSurface*>(_dataObj);
        if (!surfaceData || !_writer || !_setSurfManager) return false;
        bool writeOK = true;

        // 获取类型，写出不同类型的格式
        Interface::FITKMeshSurface::MeshSurfaceType type = surfaceData->getMeshSurfaceType();
        if (type == Interface::MeshSurfaceType::SurEle)
        {
            writeOK &= writeElementTypeSurface();
        }
        else if (type == Interface::MeshSurfaceType::SurNode)
        {
            writeOK &= writeNodeTypeSurface();
        }

        return writeOK;
    }

    bool FITKCCXAdaptorSurface::writeElementTypeSurface()
    {
        Interface::FITKMeshSurfaceElement* surfaceData = dynamic_cast<Interface::FITKMeshSurfaceElement*>(_dataObj);
        if (!surfaceData || !_writer || !_setSurfManager) return false;
        QTextStream* stream = _writer->getStream();

        _surfaceNumber++;
        QString elementSurfaceName = QString("Surf_%1").arg(_surfaceNumber);
        QString writeLine = QString("*Surface, name=%1, type=ELEMENT").arg(elementSurfaceName);

        if (surfaceData->isInternal())
        {
            _writer->consoleMessage(2, "Calculix does not support the keyword Internal when writing Element Type Surface");
        }

        // 设置表面关系映射表
        QPair<int, int> surfaceMappingKey(_mappingKeyDataObjectID, surfaceData->getDataObjectID());
        _modelInfoManager->addSurfaceMapping(surfaceMappingKey, elementSurfaceName);

        *stream << writeLine << endl;

        // 写出surface的数据 单元集, 面标识
        writeLine.clear();

        Core::FITKEnumTransfer<Interface::FITKAbaSurfaceLabel::AbaSurfLabel> surfLabel;
        int count = surfaceData->getMeshSetCount();

        // 记录set与面索引的映射
        QHash<QString, QList<int>> elSetPolygonIndexes;
        for (int i = 0; i < count; ++i)
        {
            bool ok = false;
            Interface::FITKModelSet* set = surfaceData->getMeshSetAt(i);
            auto mode = surfaceData->getModelAt(i);
            if (!set || !mode)continue;

            // 获取集合id
            QString setName = set->getDataObjectName();

            // 获取面的索引
            int polygonIndex = surfaceData->getSurfaceIndexAt(i);

            // 判断是否在set与面索引的映射里面
            if (elSetPolygonIndexes.contains(setName) && elSetPolygonIndexes.value(setName).contains(polygonIndex))continue;
            int modelId = mode->getDataObjectID();

            // 判断集合与表面的隶属关系来写出集合
            if (modelId != set->getAbsModelID() && modelId > 0)
            {
                QString name = mode->getDataObjectName();
                setName = name + "." + setName;
            }

            if (set->getAbstractModel() != nullptr && set->getAbstractModel()->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AssInstance)
            {
                QString instanceName = set->getAbstractModel()->getDataObjectName();
                _mappingKeyDataObjectID = set->getAbstractModel()->getDataObjectID();
            }

            QPair<int, int> setMappingKey(_mappingKeyDataObjectID, set->getDataObjectID());
            QString setMappingValue = _modelInfoManager->getSetMappingValue(setMappingKey);
    
            QString faceFlag{};
            if (polygonIndex != -1)
            {
                //写出面的索引
                faceFlag = shellSurfaceMapValue(surfLabel.toStrting((Interface::FITKAbaSurfaceLabel::AbaSurfLabel)polygonIndex, ok));
            }
            else
                ok = true;
            if (!ok)
                continue;

            writeLine = setMappingValue + ", " + faceFlag;
            *stream << writeLine << endl;

            // 存储set与面索引到映射
            if (elSetPolygonIndexes.contains(setName))
                elSetPolygonIndexes[setName].append(polygonIndex);
            else
                elSetPolygonIndexes.insert(setName, QList<int>() << polygonIndex);
        }
        return true;
    }

    bool FITKCCXAdaptorSurface::writeNodeTypeSurface()
    {
        Interface::FITKMeshSurfaceNode* surfaceData = dynamic_cast<Interface::FITKMeshSurfaceNode*>(_dataObj);
        if (!surfaceData || !_writer || !_setSurfManager) return false;
        //写出*surface
        QTextStream* stream = _writer->getStream();

        _surfaceNumber++;
        QString nodeSurfaceName = QString("Surf_%1").arg(_surfaceNumber);
        QString writeLine = QString("*Surface, name=%1, type=NODE").arg(nodeSurfaceName);

        // 写出不支持Internal关键字的警告
        if (surfaceData->isInternal())
        {
            _writer->consoleMessage(2, "Calculix does not support the keyword Internal when writing Node Type Surface");
        }         

        // 添加表面关系映射表
        QPair<int, int> surfaceMappingKey(_mappingKeyDataObjectID, surfaceData->getDataObjectID());
        _modelInfoManager->addSurfaceMapping(surfaceMappingKey, nodeSurfaceName);

        *stream << writeLine << endl;

        // 写出surface的数据 单元集, 面标识
        writeLine.clear();
        int count = surfaceData->getMeshSetCount();

        //记录set与面数值的映射
        QHash<QString, QList<double>> nodeSetPolygonIndexes;

        for (int i = 0; i < count; ++i)
        {
            auto d = surfaceData->getMeshSetAt(i);
            Interface::FITKModelSet* set = dynamic_cast<Interface::FITKModelSet*>(d);
            auto mode = surfaceData->getModelAt(i);
            if (!set || !mode)continue;
            int modelId = mode->getDataObjectID();

            QString setName = set->getDataObjectName();

            //获取面的数值
            double polygonValue = surfaceData->getValueAt(i);
            //判断是否在set与面数值的映射里面
            bool isExist = false;
            if (nodeSetPolygonIndexes.contains(setName))
            {
                QList<double> valueList = nodeSetPolygonIndexes.value(setName);
                for (double value : valueList)
                {
                    if (fabsl(value - polygonValue) < 1e-16)
                    {
                        isExist = true;
                        break;
                    }
                }
            }
            if (isExist)continue;
            //判断集合与表面的隶属关系来写出集合
            if (set->getAbstractModel() && mode->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::Assembly && set->getAbstractModel()->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AMTMIX)
            {
                QString instanceName = set->getAbstractModel()->getDataObjectName();
            }

            QPair<int, int> setMappingKey(modelId, set->getDataObjectID());
            QString setMappingValue = _modelInfoManager->getSetMappingValue(setMappingKey);
            if (setMappingValue == "NOT_FOUND") continue;
            QString value = _writer->double2String(surfaceData->getValueAt(i), 9);
            if (fabsl(surfaceData->getValueAt(i)) < 1e-15)
                writeLine = setMappingValue;
            else
                writeLine = setMappingValue + ", " + value;
            *stream << writeLine << endl;
             
            //存储set与面索引到映射
            if (nodeSetPolygonIndexes.contains(setName))
                nodeSetPolygonIndexes[setName].append(polygonValue);
            else
                nodeSetPolygonIndexes.insert(setName, QList<double>() << polygonValue);
        }
        return true;
    }

    int FITKCCXAdaptorSurface::getInstanceIDByName(const QString &inputInstanceName)
    {
        int instanceID = -1;
        int instanceNum = _assemblyManager->getDataCount();
        if (instanceNum < 1) return true;
        for (int i = 0; i < instanceNum; ++i)
        {
            auto instance = _assemblyManager->getDataByIndex(i);
            if (instance == nullptr) continue;

            QString instanceName = instance->getDataObjectName();

            if (instanceName == inputInstanceName)
            {
                instanceID = instance->getDataObjectID();
            }
        }
        return instanceID;
    }

    QString FITKCCXAdaptorSurface::shellSurfaceMapValue(const QString& inputValue)
    {
        QString surfaceMapValue{};

        // 创建一个映射字典
        QMap<QString, QString> mapping;
        mapping["E1"] = "S3";
        mapping["E2"] = "S4";
        mapping["E3"] = "S5";
        mapping["E4"] = "S6";

        // 查找输入值的映射
        if (mapping.contains(inputValue)) {
            surfaceMapValue = mapping.value(inputValue);
        }
        else {
            surfaceMapValue = inputValue;
        }

        return surfaceMapValue;
    }
}